package cn.blnp.net.flowable.boot.custom.timer;

import cn.blnp.net.flowable.boot.customer.flowable.handler.TimeoutReminderJobHandler;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.map.MapUtil;
import com.alibaba.fastjson2.JSONObject;
import liquibase.pro.packaged.S;
import lombok.extern.slf4j.Slf4j;
import org.flowable.common.engine.impl.interceptor.Command;
import org.flowable.common.engine.impl.interceptor.CommandContext;
import org.flowable.engine.*;
import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl;
import org.flowable.engine.repository.Deployment;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.job.service.JobServiceConfiguration;
import org.flowable.job.service.impl.asyncexecutor.JobManager;
import org.flowable.job.service.impl.persistence.entity.JobEntity;
import org.flowable.job.service.impl.persistence.entity.TimerJobEntity;
import org.flowable.job.service.impl.persistence.entity.TimerJobEntityManager;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;

/**
 * <h3>自定义作业任务处理器</h3>
 *
 * @author <a href="mailto:blnp.yibin@qq.com">lyb</a>
 * @version 1.0
 * @since 2025/6/12 17:53
 */
@Slf4j
@SpringBootTest
public class CusWorkHandlerTest {

    @Resource
    private RepositoryService repositoryService;
    @Resource
    private RuntimeService runtimeService;
    @Resource
    private IdentityService identityService;
    @Resource
    private TaskService taskService;
    @Resource
    private ProcessEngineConfigurationImpl processEngineConfiguration;
    @Resource
    private ManagementService managementService;


    /**
     *  <h1>Flowable作业处理器列表</h1>
     *  <ol>
     *      <li>
     *          <b>处理器：</b>抽象流程实例迁移作业处理器
     *          <ul>
     *              <li>实现类：</li>{@link org.flowable.engine.impl.jobexecutor.AbstractProcessInstanceMigrationJobHandler}
     *          </ul>
     *      </li>
     *      <li>
     *          <b>处理器：</b>异步完成调用活动作业处理器
     *          <ul>
     *              <li>实现类：</li>{@link org.flowable.engine.impl.jobexecutor.AsyncCompleteCallActivityJobHandler}
     *          </ul>
     *      </li>
     *      <li>
     *          <b>处理器：</b>异步节点作业处理器
     *          <ul>
     *              <li>实现类：</li>{@link org.flowable.engine.impl.jobexecutor.AsyncContinuationJobHandler}
     *          </ul>
     *      </li>
     *      <li>
     *          <b>处理器：</b>异步离开作业处理器
     *          <ul>
     *              <li>实现类：</li>{@link org.flowable.engine.impl.jobexecutor.AsyncLeaveJobHandler}
     *          </ul>
     *      </li>
     *      <li>
     *          <b>处理器：</b>异步发送事件作业处理器
     *          <ul>
     *              <li>实现类：</li>{@link org.flowable.engine.impl.jobexecutor.AsyncSendEventJobHandler}
     *          </ul>
     *      </li>
     *      <li>
     *          <b>处理器：</b>异步触发作业处理器
     *          <ul>
     *              <li>实现类：</li>{@link org.flowable.engine.impl.jobexecutor.AsyncTriggerJobHandler}
     *          </ul>
     *      </li>
     *      <li>
     *          <b>处理器：</b>BPMN历史记录清理作业处理器
     *          <ul>
     *              <li>实现类：</li>{@link org.flowable.engine.impl.jobexecutor.BpmnHistoryCleanupJobHandler}
     *          </ul>
     *      </li>
     *      <li>
     *          <b>处理器：</b>调试断点作业处理器
     *          <ul>
     *              <li>实现类：</li>{@link org.flowable.engine.impl.event.BreakpointJobHandler}
     *          </ul>
     *      </li>
     *      <li>
     *          <b>处理器：</b>该作业处理器用于计算要删除的历史流程实例的ID列表
     *          <ul>
     *              <li>实现类：</li>{@link org.flowable.engine.impl.delete.ComputeDeleteHistoricProcessInstanceIdsJobHandler}
     *          </ul>
     *      </li>
     *      <li>
     *          <b>处理器：</b>该作业器用于计算并更新已删除的历史流程实例的状态
     *          <ul>
     *              <li>实现类：</li>{@link org.flowable.engine.impl.delete.ComputeDeleteHistoricProcessInstanceStatusJobHandler}
     *          </ul>
     *      </li>
     *      <li>
     *          <b>处理器：</b>该作业处理器用于异步删除历史流程实例
     *          <ul>
     *              <li>实现类：</li>{@link org.flowable.engine.impl.delete.DeleteHistoricProcessInstanceIdsJobHandler}
     *          </ul>
     *      </li>
     *      <li>
     *          <b>处理器：</b>该作业处理器用于删除历史流程实例ID状态
     *          <ul>
     *              <li>实现类：</li>{@link org.flowable.engine.impl.delete.DeleteHistoricProcessInstanceIdsStatusJobHandler}
     *          </ul>
     *      </li>
     *      <li>
     *          <b>处理器：</b>该作业处理器用于按顺序逐个删除历史流程实例
     *          <ul>
     *              <li>实现类：</li>{@link org.flowable.engine.impl.delete.DeleteHistoricProcessInstancesSequentialJobHandler}
     *          </ul>
     *      </li>
     *      <li>
     *          <b>处理器：</b>外部工作者任务完成作业处理器
     *          <ul>
     *              <li>实现类：</li>{@link org.flowable.engine.impl.jobexecutor.ExternalWorkerTaskCompleteJobHandler}
     *          </ul>
     *      </li>
     *      <li>
     *          <b>处理器：</b>并行多实例活动完成作业处理器
     *          <ul>
     *              <li>实现类：</li>{@link org.flowable.engine.impl.jobexecutor.ParallelMultiInstanceActivityCompletionJobHandler}
     *          </ul>
     *      </li>
     *      <li>
     *          <b>处理器：</b>无等待状态的并行多实例异步离开作业处理器
     *          <ul>
     *              <li>实现类：</li>{@link org.flowable.engine.impl.jobexecutor.ParallelMultiInstanceWithNoWaitStatesAsyncLeaveJobHandler}
     *          </ul>
     *      </li>
     *      <li>
     *          <b>处理器：</b>流程事件作业处理器
     *          <ul>
     *              <li>实现类：</li>{@link org.flowable.engine.impl.jobexecutor.ProcessEventJobHandler}
     *          </ul>
     *      </li>
     *      <li>
     *          <b>处理器：</b>流程实例迁移作业处理器
     *          <ul>
     *              <li>实现类：</li>{@link org.flowable.engine.impl.jobexecutor.ProcessInstanceMigrationJobHandler}
     *          </ul>
     *      </li>
     *      <li>
     *          <b>处理器：</b>流程实例迁移状态作业处理器
     *          <ul>
     *              <li>实现类：</li>{@link org.flowable.engine.impl.jobexecutor.ProcessInstanceMigrationStatusJobHandler}
     *          </ul>
     *      </li>
     *      <li>
     *          <b>处理器：</b>定时激活流程定义处理器
     *          <ul>
     *              <li>实现类：</li>{@link org.flowable.engine.impl.jobexecutor.TimerActivateProcessDefinitionHandler}
     *          </ul>
     *      </li>
     *      <li>
     *          <b>处理器：</b>定时更新流程定义挂起状态作业处理器
     *          <ul>
     *              <li>实现类：</li>{@link org.flowable.engine.impl.jobexecutor.TimerChangeProcessDefinitionSuspensionStateJobHandler}
     *          </ul>
     *      </li>
     *      <li>
     *          <b>处理器：</b>定时启动流程实例作业处理器
     *          <ul>
     *              <li>实现类：</li>{@link org.flowable.engine.impl.jobexecutor.TimerStartEventJobHandler}
     *          </ul>
     *      </li>
     *      <li>
     *          <b>处理器：</b>定时挂起流程定义处理器
     *          <ul>
     *              <li>实现类：</li>{@link org.flowable.engine.impl.jobexecutor.TimerSuspendProcessDefinitionHandler}
     *          </ul>
     *      </li>
     *      <li>
     *          <b>处理器：</b>触发时间事件作业处理器
     *          <ul>
     *              <li>实现类：</li>{@link org.flowable.engine.impl.jobexecutor.TriggerTimerEventJobHandler}
     *          </ul>
     *      </li>
     *
     *  </ol>
     **/
    @Test
    public void test() {

    }

    /**
     *  <h2>案例演示</h2>
     **/
    @Test
    public void test1() throws InterruptedException {
        Deployment deploy = repositoryService.createDeployment()
                .addClasspathResource("flow/cusTimerWorker.bpmn20.xml")
                .name("自定义处理器演示案例")
                .deploy();
        //流程定义信息
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                .deploymentId(deploy.getId())
                .singleResult();
        log.info("流程定义ID：{}", processDefinition.getId());

        //启动参数
        Map<String, Object> variables = MapUtil.builder(new HashMap<String, Object>())
                .put("INITIATOR", "198753156055122")
                .put("userId", "198753156055122")
                .put("userName", "张三")
                .build();

        //启动多个流程实例，便于观察测试
        for (int i = 0; i < 10; i++) {
            ProcessInstance processInstance = runtimeService.startProcessInstanceById(processDefinition.getId(), variables);
            log.info("({})启动流程实例ID：{}", (i+1), processInstance.getId());
        }

        //自定义命令
        Command customTimerJobCommand = new Command<Void>() {
            @Override
            public Void execute(CommandContext commandContext) {
                //获取Job相关配置信息
                JobServiceConfiguration jobServiceConfiguration = processEngineConfiguration.getJobServiceConfiguration();
                //获取TimerJob 实体管理器
                TimerJobEntityManager timerJobEntityManager = jobServiceConfiguration.getTimerJobEntityManager();
                //创建TimeJob对象
                TimerJobEntity timer = timerJobEntityManager.create();
                timer.setProcessDefinitionId(processDefinition.getId());
                //设置TimeJob类型
                timer.setJobType(JobEntity.JOB_TYPE_TIMER);
                //设置作业处理器类型（这里是自定义的标识）
                timer.setJobHandlerType(TimeoutReminderJobHandler.TYPE);
                //设置传递给作业处理器的参数,这里我直接使用流程变量
                timer.setJobHandlerConfiguration(JSONObject.toJSONString(variables));
                //设置定时任务执行周期，即执行表达式（R/PT2M:设置为每两分钟执行一次且循环执行）
                timer.setRepeat("15 * * * * ? *");
                //设置任务的重试次数
                timer.setRetries(processEngineConfiguration.getAsyncExecutorNumberOfRetries());
                //指定当前任务处理模式为排他方式（避免并发冲突）
                timer.setExclusive(true);
                /**
                 *  设置定时任务触发时间，决定什么时候触发
                 **/
                DateTime now = DateUtil.date();
                //向后偏移一定时间后在执行
                DateTime target = now.offset(DateField.SECOND, 20);
                timer.setDuedate(target.toJdkDate());

                //保存定时人并触发
                JobManager jobManager = jobServiceConfiguration.getJobManager();
                jobManager.scheduleTimerJob(timer);
                return null;
            }
        };

        //执行自定义命令
        managementService.executeCommand(customTimerJobCommand);
        //休眠阻塞主线程，便于观察任务的执行结果
        Thread.sleep(2*60*1000);

        /**
         *  演示结果：
         * 2025-06-13 11:32:44.111  INFO 31500 --- [           main] c.b.n.f.b.c.timer.CusWorkHandlerTest     : 流程定义ID：cusTimerWorker:1:185004
         * 2025-06-13 11:32:44.171  INFO 31500 --- [           main] c.b.n.f.b.c.timer.CusWorkHandlerTest     : (1)启动流程实例ID：185005
         * 2025-06-13 11:32:44.190  INFO 31500 --- [           main] c.b.n.f.b.c.timer.CusWorkHandlerTest     : (2)启动流程实例ID：185014
         * 2025-06-13 11:32:44.214  INFO 31500 --- [           main] c.b.n.f.b.c.timer.CusWorkHandlerTest     : (3)启动流程实例ID：185023
         * 2025-06-13 11:32:44.231  INFO 31500 --- [           main] c.b.n.f.b.c.timer.CusWorkHandlerTest     : (4)启动流程实例ID：185032
         * 2025-06-13 11:32:44.247  INFO 31500 --- [           main] c.b.n.f.b.c.timer.CusWorkHandlerTest     : (5)启动流程实例ID：185041
         * 2025-06-13 11:32:44.268  INFO 31500 --- [           main] c.b.n.f.b.c.timer.CusWorkHandlerTest     : (6)启动流程实例ID：185050
         * 2025-06-13 11:32:44.283  INFO 31500 --- [           main] c.b.n.f.b.c.timer.CusWorkHandlerTest     : (7)启动流程实例ID：185059
         * 2025-06-13 11:32:44.305  INFO 31500 --- [           main] c.b.n.f.b.c.timer.CusWorkHandlerTest     : (8)启动流程实例ID：185068
         * 2025-06-13 11:32:44.336  INFO 31500 --- [           main] c.b.n.f.b.c.timer.CusWorkHandlerTest     : (9)启动流程实例ID：185077
         * 2025-06-13 11:32:44.357  INFO 31500 --- [           main] c.b.n.f.b.c.timer.CusWorkHandlerTest     : (10)启动流程实例ID：185086
         * 2025-06-13 11:33:13.706  INFO 31500 --- [ecutor-thread-1] .b.n.f.b.c.f.h.TimeoutReminderJobHandler : 截止 2025-06-13 11:33:13，张三(198753156055122) 存在 30 个未处理工作项！
         * 2025-06-13 11:33:23.642  INFO 31500 --- [ecutor-thread-2] .b.n.f.b.c.f.h.TimeoutReminderJobHandler : 截止 2025-06-13 11:33:23，张三(198753156055122) 存在 30 个未处理工作项！
         * 2025-06-13 11:34:23.725  INFO 31500 --- [ecutor-thread-3] .b.n.f.b.c.f.h.TimeoutReminderJobHandler : 截止 2025-06-13 11:34:23，张三(198753156055122) 存在 30 个未处理工作项！
         **/
    }
}
